﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SmartPowerHub.Communication.Modbus
{
    public static class ByteHelper
    {
        /// <summary>
        /// byte[]转值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="buffer">数据默认小端</param>
        /// <returns></returns>
        public static T[] GetResult<T>(this byte[] buffer, EndianFormat endianFormat = EndianFormat.ABCD)
        {
            List<T> result = new List<T>();
            try
            {
                Type targetType = typeof(T);
                Type bitType = typeof(BitConverter);
                int typeLength = Marshal.SizeOf(typeof(T));
                for (int i = 0; i < buffer.Length; i += typeLength)
                {
                    byte[] dataBuffer = buffer.ToList().GetRange(i, typeLength).ToArray();
                    dataBuffer = ByteFormat(dataBuffer, endianFormat);
                    var method = bitType.GetMethods().ToList().FirstOrDefault(m => m.ReturnType == typeof(T) && m.GetParameters().Length == 2);
                    if (method == null)
                    {
                        throw new Exception("类型转换失败");
                    }
                    T t = (T)method.Invoke(bitType, new object[] { dataBuffer, 0 });
                    result.Add(t);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return result.ToArray();
        }

        /// <summary>
        /// 值转byte[]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static byte[] GetBytes<T>(this T value, EndianFormat endianFormat = EndianFormat.ABCD, StringFormat stringFormat = StringFormat.UTF8)
        {
            Type targetType = typeof(T);

            if (targetType == typeof(string))
            {
                if (stringFormat == StringFormat.ASCII)
                {
                    byte[] utf8Bytes = Encoding.ASCII.GetBytes(value.ToString());
                    utf8Bytes = ByteFormat(utf8Bytes, endianFormat);
                    return utf8Bytes;
                }
                else
                {
                    byte[] utf8Bytes = Encoding.UTF8.GetBytes(value.ToString());
                    utf8Bytes = ByteFormat(utf8Bytes, endianFormat);
                    return utf8Bytes;
                }
            }
            else
            {
                Type bitConverterType = typeof(BitConverter);

                // 获取BitConverter中所有名为"GetBytes"的公共静态方法
                MethodInfo[] methods = bitConverterType.GetMethods(BindingFlags.Public | BindingFlags.Static)
                    .Where(m => m.Name == "GetBytes")
                    .ToArray();

                // 筛选出参数类型与目标类型匹配的方法
                MethodInfo? targetMethod = methods.FirstOrDefault(m =>
                {
                    ParameterInfo[] parameters = m.GetParameters();
                    // GetBytes方法都只有一个参数
                    return parameters.Length == 1 && parameters[0].ParameterType == targetType;
                });
                if (targetMethod == null)
                {
                    throw new Exception("类型转换失败");
                }
                // 调用找到的方法并返回结果
                byte[] bytes = (byte[])targetMethod.Invoke(null, new object[] { value })!;
                bytes = ByteFormat(bytes, endianFormat);
                return bytes;
            }
        }

        /// <summary>
        /// 字节序/字序
        /// </summary>
        /// <param name="dataBuffer">数据为小端</param>
        /// <param name="endianFormat"></param>
        /// <returns></returns>
        public static byte[] ByteFormat(this byte[] dataBuffer, EndianFormat endianFormat)
        {
            switch (endianFormat)
            {
                case EndianFormat.ABCD:
                    return dataBuffer.Reverse().ToArray();
                case EndianFormat.BADC:
                    List<byte> bytes = new List<byte>();
                    for (int n = 0; n < dataBuffer.Length; n += 2)
                    {
                        byte[] data = new byte[2];
                        data[0] = dataBuffer[n];
                        data[1] = dataBuffer[n + 1];
                        Array.Reverse(data);
                        bytes.AddRange(data);
                    }
                    return bytes.ToArray();
                case EndianFormat.CDAB:
                    byte[] cdabData = new byte[dataBuffer.Length];
                    int length = dataBuffer.Length;
                    for (int n = 0; n < dataBuffer.Length; n += 2)
                    {
                        cdabData[n] = (byte)dataBuffer[(length - 1) - n - 1];
                        cdabData[n + 1] = (byte)dataBuffer[(length - 1) - n];
                    }
                    return cdabData;
                    break;
                case EndianFormat.DCBA:
                default:
                    break;
            }
            return dataBuffer;
        }
    }
}
